package com.lhy.tool.model.factory;

import com.lhy.tool.autoconfigation.GeneratorProperties;
import com.lhy.tool.database.Table;
import com.lhy.tool.database.TableColumn;
import com.lhy.tool.database.table.DbMetaDataFactory;
import com.lhy.tool.model.CrudBean;
import com.lhy.tool.model.CrudColumn;
import com.lhy.tool.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

@Component
@Slf4j
public class CrudBeanFactory {

    @Autowired
    GeneratorProperties generatorProperties;

    List<CrudBean> crudBeans;

    @Autowired
    DbMetaDataFactory dbMetaDataFactory;

    public List<CrudBean> buildCrudBeans() {
        init();
        check();
        List<Table> tables = getTables();
        processTable(tables);
        return crudBeans;
    }

    private void init() {
        this.crudBeans = generatorProperties.getModelAttributes().stream()
                .map(modelAttributes -> newCrudBean(generatorProperties, modelAttributes)).collect(Collectors.toList());
    }

    private void check() {
        if (CollectionUtils.isEmpty(crudBeans)) {
            throw new NullPointerException("至少需要一个crudBeans模型");
        }
        log.info("crudBean数量：{}", crudBeans.size());
        crudBeans.forEach(crudBean -> log.info("crudBean: {}", crudBean.toString()));
    }

    private List<Table> getTables() {
        return dbMetaDataFactory.dbMetaDataProcessor().listTable(crudBeans.stream().map(CrudBean::getTableName).collect(Collectors.toList()));
    }

    private void processTable(List<Table> tables) {
        Assert.notEmpty(tables, "从数据库匹配到表为空");
        crudBeans.forEach(crudBean -> tables.stream().filter(tableInfo -> this.matchEquals(crudBean.getTableName(), tableInfo.getName())).findFirst().ifPresent(table -> {
            crudBean.setTable(table);
            String comment1 = table.getComment();
            if (StringUtils.hasText(comment1)) {
                String comment = comment1.endsWith("表") ? comment1.substring(0, comment1.length() - 1) : comment1;
                crudBean.setDescription(comment);
            }else{
                crudBean.setDescription("");
            }
            List<CrudColumn> crudColumns = table.getColumns().stream().map(tableColumn -> {
                CrudColumn crudColumn = new CrudColumn().setDbColumnName(tableColumn.getName())
                        .setColumnName(StringUtil.underlineToCamel(tableColumn.getName().toLowerCase()))
                        .setColumnDesc(tableColumn.getComment()).setPrimary(tableColumn.getKeyFlag())
                        .setColumnType(tableColumn.getColumnType().getType());
                processColumnAttr(crudBean, crudColumn);
                processColumnTableColumn(crudColumn, table.getColumns());
                return crudColumn;
            }).sorted(Comparator.comparingInt(col -> col.getColumnAttributes().getIndex())).collect(Collectors.toList());
            crudBean.setColumns(crudColumns);
        }));
    }

    private boolean matchEquals(String str1, String str2) {
        if (generatorProperties.getGlobalConfig().getIgnoreCase()) {
            return str1.equalsIgnoreCase(str2);
        }
        return str1.equals(str2);
    }

    private CrudBean newCrudBean(GeneratorProperties generatorProperties, GeneratorProperties.ModelAttributes modelAttributes) {
        CrudBean crudBean = new CrudBean();
        this.initBeanProperties(crudBean, generatorProperties, modelAttributes);
        return crudBean;
    }


    private void initBeanProperties(CrudBean crudBean, GeneratorProperties generatorProperties, GeneratorProperties.ModelAttributes modelAttributes) {
        crudBean.setTableName(modelAttributes.getTableName());
        if (!StringUtils.hasText(modelAttributes.getEntityName())) {
            crudBean.setSimpleName(StringUtil.underlineToCamel(modelAttributes.getTableName()));
        } else {
            crudBean.setSimpleName(modelAttributes.getEntityName());
        }
        crudBean.setFullName(generatorProperties.getGlobalConfig().getPackageName() + "." + modelAttributes.getModuleName() + "." + modelAttributes.getEntityName())
                .setModelAttributes(modelAttributes);
    }

    private void processColumnAttr(CrudBean crudBean, CrudColumn crudColumn) {
        //覆盖配置文件属性
        crudBean.getModelAttributes().getColumnAttrMap().forEach((columnName, columnAttributes) -> {
            if (matchEquals(crudColumn.getColumnName(), columnName)) {
                crudColumn.setColumnAttributes(columnAttributes);
                if (StringUtils.hasText(columnAttributes.getAlias())) {
                    crudColumn.setColumnDesc(columnAttributes.getAlias());
                }
            }
        });
    }

    private void processColumnTableColumn(CrudColumn crudColumn, List<TableColumn> tableColumns) {
        tableColumns.stream().filter(tableColumn -> matchEquals(crudColumn.getDbColumnName(), tableColumn.getName())).forEach(crudColumn::setTableColumn);
    }


}
